{-# LANGUAGE CPP #-}
module Game.Trubis.PipeSection (
  PipeSection(),
  rotate,
  outputDirections,
  outputDirectionBits,
) where

import Game.Trubis.Position
import Data.Word.Odd
import System.Random.Stateful
import Data.Bits hiding (rotate)

newtype PipeSection = PipeSection
  { outputDirectionBits :: Word4
  -- ^ See source code of `outputDirections` for each bit meaning.
  -- prop> forall (s :: PipeSection). outputDirectionBits s /= 0
  }

instance Uniform PipeSection where
  uniformM random = do
#ifdef UNIFORM_PIPE_SECTION_IS_ISOMORPHIC_TO_ROTATE
    nOutputs <- uniformRM (1, 4 :: Word) random
    let b = (fromIntegral :: Word -> Word4) $ 2 ^ nOutputs - 1
    PipeSection <$> (b `rotateL`) <$> uniformRM (0, 3) random
#else
    PipeSection . fromIntegral <$> uniformRM (0x01, 0x0F :: Word) random
#endif

rotate :: PipeSection -> PipeSection
rotate PipeSection{..} = PipeSection $ outputDirectionBits `rotateL` 1

outputDirections :: PipeSection -> [Direction]
outputDirections PipeSection{..} =
  map fst . filter (\(_, bit) -> outputDirectionBits `testBit` bit) $ zip
    -- `outputDirectionBits` meaning:
    [down, left, up, right]
    [   3,    2,  1,     0]

